﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace MVVMFramework.ViewModel
{
    /// <summary>
    /// Contains additional information about any enumeration. 
    /// Used to display user friendly header of the concrete enumeration value. 
    /// It is possible to create inherited class and add properties and localize headers of the enum values
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class EnumInfo<T> : IComparable where T : struct,IComparable
    {
        #region Ctors

        /// <summary>
        /// Initializes a new instance of the <see cref="EnumInfo&lt;T&gt;"/> class.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="name">The text associated with the enumeration value.</param>
        public EnumInfo(T value, string name)
        {
            Value = value;
            Name = name ?? addSpacesToSentence(value.ToString());
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="EnumInfo&lt;T&gt;"/> class.
        /// </summary>
        /// <param name="value">The value.</param>
        public EnumInfo(T value)
            : this(value, addSpacesToSentence(value.ToString()))
        {
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets the value of the enum
        /// </summary>
        public T Value
        {
            get;
            protected set;
        }

        /// <summary>
        /// Gets a user friendly Name of the concrete value of the enum
        /// </summary>
        public string Name
        {
            get;
            protected set;
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            return Name ?? "";
        }

        /// <summary>
        /// Gets the enumeration information.
        /// </summary>
        /// <typeparam name="TInfo">The type of the class contained information about enumeration value.</typeparam>
        /// <param name="creation">The function to create instance of the specified type.</param>
        /// <returns></returns>
        public static IEnumerable<TInfo> GetEnumInfos<TInfo>(Func<T, TInfo> creation) where TInfo : EnumInfo<T>
        {
            List<TInfo> infos = new List<TInfo>();
            foreach (T ms in Enum.GetValues(typeof(T)))
            {
                TInfo info = creation != null ? creation.Invoke(ms) : null;

                if (info != null)
                    infos.Add(info);
            }

            return infos;
        }

        #endregion

        #region Private Methods

        private static string addSpacesToSentence(string text)
        {
            if (string.IsNullOrWhiteSpace(text))
                return "";

            StringBuilder newText = new StringBuilder(text.Length * 2);

            newText.Append(text[0]);
            for (int i = 1; i < text.Length; i++)
            {
                if (char.IsUpper(text[i]) && (!char.IsUpper(text[i - 1]) || (i + 1 < text.Length && !char.IsUpper(text[i + 1]))))
                    newText.Append(' ');
                newText.Append(text[i]);
            }
            return newText.ToString();
        }

        #endregion

        public int CompareTo(object obj)
        {
            if (obj == null)
                return 1;
            var castObj = obj as EnumInfo<T>;
            if (castObj == null)
                throw new ArgumentException("An object to compare with this instance is not the same type as this instance.");

            return Value.CompareTo(castObj.Value);
        }
    }
}